package com.yzqp.blog.config;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.yzqp.blog.interceptor.DefaultInterceptor;
import com.yzqp.blog.interceptor.IndexInterceptor;
import com.yzqp.common.mvc.httpmessage.BooleanFastJsonHttpMessageConverter;
import com.yzqp.common.mvc.httpmessage.EnumFastJsonHttpMessageConverter;
import com.yzqp.common.mvc.httpmessage.StringToEnumConverterFactory;
import com.yzqp.common.util.ClassUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Configuration
//@Component
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private DefaultInterceptor defaultInterceptor;

//    @Resource
//    private ImsInterceptor imsInterceptor;

    @Value("${swagger.enable}")
    private boolean swaggerEnable;

    @Resource
    private IndexInterceptor indexInterceptor;

    @Autowired
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter;

    /**
     * 添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 后台拦截器
//        registry.addInterceptor(imsInterceptor)
//                .addPathPatterns("/ims/**")
//                .excludePathPatterns("/ims/pub/**");

        // 前台拦截器
//        registry.addInterceptor(indexInterceptor)
//                .addPathPatterns("/web/index/**")
//                .excludePathPatterns("/web/index/pub/miniProgramLogin")
//                .excludePathPatterns("/web/index/pub/backLogin");

        // swagger 路径
        String[] swaggerPaths = new String[]{};
        if (swaggerEnable) {
            swaggerPaths = new String[]{
                    "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/swagger-ui.html", "/doc.html", "/doc.html/**"
            };
        }

        // 默认拦截器拦截所有
//        registry.addInterceptor(defaultInterceptor)
//                .addPathPatterns("/**")
//                .excludePathPatterns("/ims/**")
//                .excludePathPatterns("/test/**")
//                .excludePathPatterns("/web/index/**")
//                .excludePathPatterns(swaggerPaths)
//                .excludePathPatterns("/wxpay/**")
//                .excludePathPatterns("/alipay/**")
//                .excludePathPatterns("/error")
//                .excludePathPatterns("/10000");
    }

//    @Override
//    public void addResourceHandlers(ResourceHandlerRegistry registry) {
//        // 上传目录映射
//        registry.addResourceHandler("/upload/**").addResourceLocations("file:" + YzRuntimePath.getUploadPath("") + "/");
//
//        // swagger资源映射
//        if (swaggerEnable) {
//            registry.addResourceHandler("swagger-ui.html")
//                    .addResourceLocations("classpath:/META-INF/resources/");
//            registry.addResourceHandler("/webjars/**")
//                    .addResourceLocations("classpath:/META-INF/resources/webjars/");
//        }
//    }

    /**
     * 同源处理
     *
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true).allowedHeaders("*")
                .allowedMethods("*")
                .maxAge(3600);
    }

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }

    /**
     * 扫描枚举包
     *
     * @return 所有枚举类的类类型
     */
    @Bean
    List<Class<?>> enumValues() {
        List<Class<?>> list = new ArrayList<>();
        Set<Class<?>> set = ClassUtil.getClasses("com.yzqp.characterillation.pojo.enums");
        for (Class<?> clazz : set) {
            list.add(clazz);
        }
        return list;
    }

    /**
     * 只能处理application/json类型的数据 => body(请求体)的数据) => @RequestBody的数据
     *
     * @return
     */
    @Bean
    FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        System.out.println("fastJsonHttpMessageConverter...................");

        FastJsonConfig config = new FastJsonConfig();
        config.setSerializerFeatures(SerializerFeature.QuoteFieldNames,
                SerializerFeature.WriteMapNullValue,//保留空的字段
                SerializerFeature.WriteNullListAsEmpty,//List null-> []
                SerializerFeature.WriteDateUseDateFormat,// 日期格式化
                SerializerFeature.WriteNullStringAsEmpty);//String null -> "");

        // TODO 这里只是为了测试, 最好都通过扫描来查找而不是硬编码
        // enumValues.add(Sex.class);
        List<Class<?>> enumValues = enumValues();
        if (enumValues != null && enumValues.size() > 0) {
            // 枚举类型字段：序列化反序列化配置
            EnumFastJsonHttpMessageConverter enumConverter = new EnumFastJsonHttpMessageConverter();
            ParserConfig parserConfig = config.getParserConfig();
            SerializeConfig serializeConfig = config.getSerializeConfig();
            for (Class<?> clazz : enumValues) {
                parserConfig.putDeserializer(clazz, enumConverter);
                serializeConfig.put(clazz, enumConverter);
            }
        }

        //boolean 值进行反序列化
        BooleanFastJsonHttpMessageConverter stringToBooleanHttpMessageConverter = new BooleanFastJsonHttpMessageConverter();
        ParserConfig parserConfig = config.getParserConfig();
        SerializeConfig serializeConfig = config.getSerializeConfig();
        parserConfig.putDeserializer(Boolean.class, stringToBooleanHttpMessageConverter);
        serializeConfig.put(Boolean.class, stringToBooleanHttpMessageConverter);

        //创建 FastJsonHttpMessageConverter
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        converter.setFastJsonConfig(config);
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        List<MediaType> mediaTypeList = new ArrayList<>();
        mediaTypeList.add(MediaType.APPLICATION_JSON_UTF8);
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        mediaTypeList.add(MediaType.ALL);
        converter.setSupportedMediaTypes(mediaTypeList);

        return converter;
    }

    /**
     * 只能处理application/x-www-form-urlencoded类型的数据 => url(路径)的数据) => @RequestParam的数据
     *
     * @return
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        System.out.println("addFormatters................");
        registry.addConverterFactory(new StringToEnumConverterFactory());
    }


    /**
     * 只能处理application/json类型的数据 => body(请求体)的数据) => @RequestBody的数据
     *
     * @return
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        System.out.println("configureMessageConverters.................");

        converters.add(fastJsonHttpMessageConverter);
    }
}
